
#include "Image.h"

#include "CodeMethod.h"
#include <map>
#include "Class.h"
#include "InterpretPrescription.h"
#include "util.h"
using namespace std;
void CodeMethod::add(Statement codeBlock){
   //printf("Method %s: ",selector.c_str());
//   print_stmt(image,codeBlock);
   //printf("\n");
   code.push_back(codeBlock);
}
Object* execute_expr(Expression* e,Image* img,Object* self,map<string,Object*>* temps){
   if(e->type==EXPRESSION_MESSAGE){
      Object* receiver=execute_expr(e->message->object,img,self,temps);
      //printf("Sending message to %s.\n",((Class*)receiver->getClass())->getName().c_str());
      int argc=e->message->arguments.size();
      Object** argv=new Object*[argc];
      for(int i=0;i<argc;i++){
         argv[i]=execute_expr(e->message->arguments[i],img,self,temps);
      }
      return receiver->send(img,e->message->selector,argc,argv);
   }else if(e->type==EXPRESSION_VAR){
      if(e->var=="null"){
          return NULL;
      }else if(temps->find(e->var)!=temps->end()){
         return (*temps)[e->var];
      }else if(self->getClass(img)->hasField(e->var)){
          return self->get(e->var);
      }else if(img->getObject(e->var)!=NULL){
          return img->getObject(e->var);
      }else{
         printf("ERROR: var %s not found.\n",e->var.c_str());
      }
   }else if(e->type==EXPRESSION_SELF){
      return self;
   }else if(e->type==EXPRESSION_CONST){
      return e->constant;
   }else if(e->type==EXPRESSION_CLOSURE){
       InterpretClosure* closure=new InterpretClosure();
       img->clsIClosure->initializeObject(closure);
       closure->self=self;
       closure->context=*temps;
       closure->prescription=e->cp;
       return closure;
   }else{
       printf("ERROR: unknow expression\n");
   }
}
Object* CodeMethod::execute(Image* img,Object* self,int argc,Object** argv){
   map<string,Object*> temps;
   //import arguments
   if(argc!=args.size()) printf("ERROR: wrong number of arguments.\n");
   for(int i=0;i<argc;i++){
      temps[argumentsNames[i]]=argv[i];
   }
   list<Statement>::iterator it=code.begin();
   while(it!=code.end()){
      Statement st=*it;
      Object* obj=execute_stmt(st,img,self,&temps);
      if(obj!=NULL) return obj;
      it++;
   }
   return NULL;
}
Object* execute_stmt(Statement st,Image* img,Object* self,map<string,Object*>* temps){
      Object* rvalue=execute_expr(st.rvalue,img,self,temps);
      if(st.type==STATEMENT_ASSIGN){
         if(self->getClass(img)->hasField(st.lvalue)){
             self->set(st.lvalue,rvalue);
         }else{
            (*temps)[st.lvalue]=rvalue;
         }
         return NULL;
      }else if(st.type==STATEMENT_RETURN){
         return rvalue;
      }else if(st.type==STATEMENT_DISCARD){
          return NULL;
      }else{
          printf("ERROR: unknown statemen %d.",st.type);
      }
}
void CodeMethod::addArgument(Type* type,string name){
   args.push_back(type);
   argumentsNames.push_back(name);
}
void CodeMethod::addTemp(string name,Type* type){
   temps[name]=type;
}
void print_stmt(Image* image,Statement stmt){
   if(stmt.type==STATEMENT_ASSIGN){
      printf("%s:=",stmt.lvalue.c_str());
   }else if(stmt.type==STATEMENT_RETURN){
      printf("^");
   }
   print_expr(image,stmt.rvalue);
}
void print_expr(Image* image,Expression* expr){
   if(expr->type==EXPRESSION_MESSAGE){
      MessageSend* m=expr->message;
      printf("(");
      print_expr(image,m->object);
      printf(" %s",m->selector.c_str());
      vector<Expression*>::iterator it=m->arguments.begin();
      while(it!=m->arguments.end()){
         printf(" ");
         print_expr(image,*it);
         it++;
      }
      printf(")");
   }else if(expr->type==EXPRESSION_VAR){
      printf("%s",expr->var.c_str());
   }else if(expr->type==EXPRESSION_SELF){
      printf("self");
   }else if(expr->type==EXPRESSION_CONST){
      printObject(image,expr->constant);
   }else if(expr->type==EXPRESSION_CLOSURE){
      expr->cp->print(image);
   }
}
Expression* ast_closure(InterpretPrescription* cp){
   Expression* e=new Expression();
   e->type=EXPRESSION_CLOSURE;
   e->cp=cp;
   return e;
}
Expression* ast_const(Object* o){
   Expression* e=new Expression();
   e->type=EXPRESSION_CONST;
   e->constant=o;
   return e;
}
Expression* ast_message(Expression* object,string selector,int count,...){
   Expression* e=new Expression();
   e->type=EXPRESSION_MESSAGE;
   MessageSend* m=new MessageSend();
   e->message=m;
   m->object=object;
   m->selector=selector;
   vector<Expression*> lst;
   for(int i=0;i<count;i++){
      Expression** pcount= (Expression**) ((&count)+1 );
      Expression* e=pcount[i];
      lst.push_back(e);
      m->arguments=lst;
   }
   return e;
}
Expression* ast_self(){
   Expression* e=new Expression();
   e->type=EXPRESSION_SELF;
   return e;
}
Expression* ast_var(string temp){
   Expression* e=new Expression();
   e->type=EXPRESSION_VAR;
   e->var=temp;
   return e;
}
Statement ast_assign(string lvalue,Expression* expr){
   Statement s;
   s.type=STATEMENT_ASSIGN;
   s.lvalue=lvalue;
   s.rvalue=expr;
   return s;
}
Statement ast_discard(Expression* expr){
   Statement s;
   s.type=STATEMENT_DISCARD;
   s.rvalue=expr;
   return s;
}
Statement ast_return(Expression* expr){
   Statement s;
   s.type=STATEMENT_RETURN;
   s.rvalue=expr;
   return s;
}
CodeMethod::CodeMethod(Image* image,string selector,Class* cls):Method(image,selector,cls){
    //printf("Cmethod sel %s\n",selector.c_str());
}
